//
// Created by Chiro on 2022/2/26.
//

/**
 * 此文件能够依照宏配置决定当前模块的运行模式：
 * 1. RTL 模式，仅运行 Verilator
 * 2. Software Model 模式：仅运行软件模型
 * 3. Difftest 模式：RTL 和 Software Model 同时运行，并且进行差分测试
 */

#ifndef CHISEL_X_DUMMY2_HPP
#define CHISEL_X_DUMMY2_HPP

#include <common.h>
#include <Dummy2.h>

#ifndef USE_MODEL
#include <verilated.h>
#else

#include <model.h>

#ifndef IS_DIFF_ON
#define IS_DIFF_ON IS_DIFF(Dummy2)
#endif
#define VerilatedTargetDummy2 MUXDEF(IS_DIFF_ON, VerilatedDiff<Dummy2>, VerilatedFake)

class Dummy2_sm : public VerilatedTargetDummy2 {
public:
  uint8_t io_in_a{}, io_in_b{}, io_out_c{};
  uint8_t cnt{};

  Dummy2_sm() : VerilatedTargetDummy2() {}

#if IS_DIFF_ON

  void dut_load() override {
    dut->clock = clock, dut->reset = reset;
    dut->io_in_a = io_in_a, dut->io_in_b = io_in_b;
    dut->eval();
  }

  void dut_apply() override {
    clock = dut->clock;
    reset = dut->reset;
    io_in_a = dut->io_in_a, io_in_b = dut->io_in_b;
    io_out_c = dut->io_out_c;
  }

  bool dut_check() override {
    if (dut->io_out_c != io_out_c) {
      Log("DUT Check Diff at c: REF <> DUT - 0x%02X <> 0x%02X", io_out_c, dut->io_out_c);
      return false;
    }
    return true;
  }

#endif

  void eval() override {
    static uint8_t clock_last = 1;
    IFDEF(IS_DIFF_ON, dut_load());
    // on rising edge
    if (clock_last == 0 && clock == 1) {
      io_out_c = io_in_a ^ io_in_b;
    }
    clock_last = clock;
    IFDEF(IS_DIFF_ON, Assert(dut_check(), "DUT Assert Failed"));
  }
};

#define Dummy2 Dummy2_sm
#ifndef Verilated
#define Verilated VerilatedTargetDummy2
#endif
#endif

#endif //CHISEL_X_DUMMY2_HPP
